#include "gbDlist/gb-dlist.h"

#include "glib-object.h"
#include "glib.h"

#define GB_DLIST_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, GB_TYPE_DLIST, GBDListPrivate))

// (类名，类方法前缀，父类型)
G_DEFINE_TYPE(GBDList, gb_dlist, G_TYPE_OBJECT);

// 定义枚举属性
typedef enum _GB_DLIST_PROPERTY {
    PROP_DLIST_0,  // not use
    PROP_DLIST_HEAD,
    PROP_DLIST_HEAD_PREV,
    PROP_DLIST_HEAD_NEXT,
    PROP_DLIST_TAIL,
    PROP_DLIST_TAIL_PREV,
    PROP_DLIST_TAIL_NEXT
} GB_DLIST_PROPERTY;

typedef struct _GBDListNode {
    struct _GBDListNode *prev;
    struct _GBDListNode *next;
    gpointer             data;
} GBDListNode;

typedef struct _GBDListPrivate {
    GBDListNode *head;
    GBDListNode *tail;
} GBDListPrivate;

static void gb_dlist_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) {
    // 基类转换为子类
    GBDList        *self = GB_DLIST(obj);
    GBDListPrivate *priv = GB_DLIST_GET_PRIVATE(self);
    switch (prop_id) {
        case PROP_DLIST_HEAD:
            priv->head = g_value_get_pointer(value);
            break;
        case PROP_DLIST_HEAD_PREV:
            priv->head->prev = g_value_get_pointer(value);
            break;
        case PROP_DLIST_HEAD_NEXT:
            priv->head->next = g_value_get_pointer(value);
            break;
        case PROP_DLIST_TAIL:
            priv->tail = g_value_get_pointer(value);
            break;
        case PROP_DLIST_TAIL_PREV:
            priv->tail->prev = g_value_get_pointer(value);
            break;
        case PROP_DLIST_TAIL_NEXT:
            priv->tail->next = g_value_get_pointer(value);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
            break;
    }
}

static void gb_dlist_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) {
    GBDList        *self = GB_DLIST(obj);
    GBDListPrivate *priv = GB_DLIST_GET_PRIVATE(self);
    switch (prop_id) {
        case PROP_DLIST_HEAD:
            g_value_set_pointer(value, priv->head);
            break;
        case PROP_DLIST_HEAD_PREV:
            g_value_set_pointer(value, priv->head->prev);
            break;
        case PROP_DLIST_HEAD_NEXT:
            g_value_set_pointer(value, priv->head->next);
            break;
        case PROP_DLIST_TAIL:
            g_value_set_pointer(value, priv->tail);
            break;
        case PROP_DLIST_TAIL_PREV:
            g_value_set_pointer(value, priv->tail->prev);
            break;
        case PROP_DLIST_TAIL_NEXT:
            g_value_set_pointer(value, priv->tail->next);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
            break;
    }
}

static void gb_dlist_init(GBDList *self) {
    g_print("GBDList Object Initialization\n");
}

static void gb_dlist_class_init(GBDListClass *class) {
    g_print("GBDListClass Struct Initialization\n");

    // 添加私有成员到类结构体中
    g_type_class_add_private(class, sizeof(GBDListPrivate));

    // 替换类结构体中原类属性，此处为函数指针
    GObjectClass *base_class = G_OBJECT_CLASS(class);
    base_class->set_property = gb_dlist_set_property;
    base_class->get_property = gb_dlist_get_property;

    // 安装可外部访问的属性
    GParamSpec *pspec;
    pspec = g_param_spec_pointer("head",
                                 "Head node",
                                 "The head node of the double list",
                                 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
    g_object_class_install_property(base_class, PROP_DLIST_HEAD, pspec);
    pspec = g_param_spec_pointer("head-prev",
                                 "The previous node of the head node",
                                 "The previous node of the head node of the double list",
                                 G_PARAM_READABLE | G_PARAM_WRITABLE);
    g_object_class_install_property(base_class, PROP_DLIST_HEAD_PREV, pspec);
    pspec = g_param_spec_pointer("head-next",
                                 "The next node of the head node",
                                 "The next node of the head node of the double list",
                                 G_PARAM_READABLE | G_PARAM_WRITABLE);
    g_object_class_install_property(base_class, PROP_DLIST_HEAD_NEXT, pspec);
    pspec = g_param_spec_pointer("tail",
                                 "Tail node",
                                 "The tail node of the double list",
                                 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT);
    g_object_class_install_property(base_class, PROP_DLIST_TAIL, pspec);
    pspec = g_param_spec_pointer("tail-prev",
                                 "The previous node of the tail node",
                                 "The previous node of the tail node of the double list",
                                 G_PARAM_READABLE | G_PARAM_WRITABLE);
    g_object_class_install_property(base_class, PROP_DLIST_TAIL_PREV, pspec);
    pspec = g_param_spec_pointer("tail-next",
                                 "The next node of the tail node",
                                 "The next node of the tail node of the double list",
                                 G_PARAM_READABLE | G_PARAM_WRITABLE);
    g_object_class_install_property(base_class, PROP_DLIST_TAIL_NEXT, pspec);
}